package ar.uba.fi.tonyvaliente.tree;

//import java.util.BitSet;
import java.util.Iterator;
import java.util.List;

import ar.uba.fi.tonyvaliente.files.File;
import ar.uba.fi.tonyvaliente.files.FileBlock;
import ar.uba.fi.tonyvaliente.files.FileRecord;
import ar.uba.fi.tonyvaliente.files.RecordPosition;
//import ar.uba.fi.tonyvaliente.persistors.BitSetPersistor;
import ar.uba.fi.tonyvaliente.persistors.IntegerPersistor;
//import ar.uba.fi.tonyvaliente.utils.io.ByteCompletionMode;

public class BTreeFileInspector {
	
	private static BTreeNodePersistor<Integer, Integer> nodePersistor;

	public static void main(String[] args) {
		try {
			String fileName = args[0];
			System.out.println("Leyendo archivo: " + fileName + "...");
			System.out.println();
			
			File file = File.open(fileName, true);
			
			// Imprimo informacion general del archivo (cabecera)
			imprimirInfoGeneral(file);
			
			// Imprimo informacion de los registros
			imprimirInfoRegistros(file);
			
			file.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	private static void imprimirInfoGeneral(File file) throws Exception {
		System.out.println("*** INFORMACION GENERAL DEL ARCHIVO ***");
		System.out.println();
		System.out.println("Tamaño de bloque: " + file.getBlockSize());
		System.out.println("Cantidad de bloques: " + file.getBlockCount());
		System.out.println("Posicion del nodo raiz: " + file.getProperty("rootNodeBlockNumber")
				+ "," + file.getProperty("rootNodeOffset"));
		System.out.println("Maxima cant.elem.nodo: " + file.getProperty("maxCantElementosNodo"));
		System.out.println();
		System.out.println();
	}
	
	private static void imprimirInfoRegistros(File file) throws Exception {
		System.out.println("*** INFORMACION DE LOS REGISTROS ***");
		System.out.println();
		
		nodePersistor = new BTreeNodePersistor<Integer, Integer>(new IntegerPersistor(), new IntegerPersistor(), null);
		
		for (int i = 0; i < file.getBlockCount(); i++) {
			FileBlock block = file.getBlock(i);
			System.out.printf("Bloque %d - Libres: %d\n", i, block.getFreeBytes());
			for (int j = 0; j < block.getRecordCount(); j++) {
				FileRecord record = block.getRecord(j);
				byte[] data = record.getData();
				imprimirInfoRegistro(i, j, data);
			}
		}
	}
	
	private static void imprimirInfoRegistro(int block, int offset, byte[] data)
			throws Exception {

		BTreeNode<Integer, Integer> node = nodePersistor.deserialize(data);
		System.out.printf("Nodo %d,%d: (%d bytes, %d elem) ",
				block, offset, data.length, node.getCantidadElementos());
		
		// Info del padre
		DiskBReference<Integer, Integer> parentRef = (DiskBReference<Integer, Integer>)node.getParent();
		if (parentRef != null) {
			RecordPosition pos = parentRef.getRecordPosition();
			System.out.printf("[Padre = %d,%d]", pos.getBlockNumber(), pos.getOffset());
		} else {
			System.out.print("[Padre = null] ");
		}
		
		// Datos
		System.out.print("{");
		Iterator<Integer> i = node.getDatos().keySet().iterator();
		while (i.hasNext()) {
			Integer key = i.next();
			System.out.print(key);
			if (i.hasNext()) {
				System.out.print(',');
			}
		}
		System.out.print("}");
		
		// Referencias
		List<BReference<Integer, Integer>> references = node.getReferences();
		System.out.print(" [Hijos: ");
		Iterator<BReference<Integer, Integer>> it = references.iterator();
		while (it.hasNext()) {
			BReference<Integer, Integer> ref = it.next();
			if (ref != null) {
				DiskBReference<Integer, Integer> diskRef = (DiskBReference<Integer, Integer>)ref;
				RecordPosition pos = diskRef.getRecordPosition();
				if (pos != null) {
					System.out.printf("(%d,%d)", pos.getBlockNumber(), pos.getOffset());
				} else {
					System.out.println("(null)");
				}
			} else {
				System.out.print("null");
			}
			if (it.hasNext()) {
				System.out.print(',');
			}
		}
		System.out.println("]");
		System.out.flush();
	}

}
